
//Copyright 1997-2009 Syrinx Development, Inc.
//This file is part of the Syrinx Web Application Framework (SWAF).
// == BEGIN LICENSE ==
//
// Licensed under the terms of any of the following licenses at your
// choice:
//
//  - GNU General Public License Version 3 or later (the "GPL")
//    http://www.gnu.org/licenses/gpl.html
//
//  - GNU Lesser General Public License Version 3 or later (the "LGPL")
//    http://www.gnu.org/licenses/lgpl.html
//
//  - Mozilla Public License Version 1.1 or later (the "MPL")
//    http://www.mozilla.org/MPL/MPL-1.1.html
//
// == END LICENSE ==
using System;
using System.Collections;
using System.Xml;

using Swaf;
using Swaf.BizObj;
using Swaf.BizObj.basic;
using Swaf.Container;
using Swaf.DataAccess;

namespace Swaf.BizObj.Virtual
{
	/// <summary>
	/// Summary description for VirtualBizObjList.
	/// </summary>
	[Serializable]
	public abstract class VirtualBizObjList : BaseBizObjList, IGroupedBizObjList
	{
		private IBizObjList m_groups;
		private int m_targetGroupSize = -1;
		private object m_id;
		private string m_groupBizObjType = "BizObjListGroup";
		private IBizObjDefinition m_objType;

		public VirtualBizObjList(object id, int targetGroupSize, string groupBizObjType, string bizObjType)
		{
			m_id = id;
			m_targetGroupSize = targetGroupSize;
			if(groupBizObjType != null && groupBizObjType.Length > 0)
				m_groupBizObjType = groupBizObjType;
			m_objType = Application.currentApp.bizObjMgr.getDefinition(bizObjType);
		}

		protected abstract IBizObjList getBasicGroupList(object id);
		protected abstract void ensureChildrenAvailable(IBizObjList groups, IBizObj group);
		protected abstract IBizObj initializeNewGroup(IBizObjList groups);
		protected abstract void updateGroup(IBizObj group);

		protected void initialize()
		{
			m_groups = getBasicGroupList(m_id);
		}

		public override IBizObj this[int index]
		{
			get
			{
				int pos = 0;
				for(int x = 0; x < m_groups.numElements;++x)
				{
					IBizObj group = m_groups[x];
					int groupCount = (int)group.get("numChildren");
					if(pos + groupCount > index)
					{
						ensureChildrenAvailable(m_groups, group);
						return ((IBizObjList)group.get("children"))[index-pos];
					}
					pos += groupCount;
				}
				throw new Exception("Out of range");
			}
			set
			{
			}
		}

		private IBizObj getNextInsertGroup()
		{
			IBizObj lastGroup = null;
			
			if(m_groups.numElements > 0)
			{
				lastGroup = m_groups[m_groups.numElements -1];
				if((int)lastGroup.get("numChildren") < m_targetGroupSize)
					ensureChildrenAvailable(m_groups, lastGroup);
				else
					lastGroup = initializeNewGroup(m_groups);
			}
			else
				lastGroup = initializeNewGroup(m_groups);

			return lastGroup;
		}

		public override IBizObj insertNew()
		{
			IBizObj lastGroup = getNextInsertGroup();
			if(lastGroup != null)
				return ((IBizObjList)lastGroup.get("children")).insertNew();

			return null;
		}

		public override int Add(object value)
		{
			IBizObj lastGroup = getNextInsertGroup();
			if (lastGroup != null)
				return ((IBizObjList)lastGroup.get("children")).Add(value);
			return 0;
		}

		public override int numElements 
		{
			get
			{
				int pos = 0;
				foreach(IBizObj group in m_groups)
				{
					int groupCount = (int)group.get("numChildren");
					pos += groupCount;
				}
				return pos;
			}
		}

		public override IBizObj insertNewMakeCopy(IBizObj obj)
		{
			IBizObj lastGroup = getNextInsertGroup();
			if(lastGroup != null)
				return ((IBizObjList)lastGroup.get("children")).insertNewMakeCopy(obj);

			return null;
		}

		public override IBizObjDefinition objectType
		{
			get
			{
				return m_objType;
			}
		}

		public override void refresh()
		{
		}

		public override string getXml(string name, bool setOnly, bool dirtyOnly, bool newOnly, bool getBasic, bool getObjs, bool getILists, bool getSysVals, XmlTextWriter xmlOut)
		{
			return getXml(name, "ExternalUntrusted", setOnly, dirtyOnly, newOnly, getBasic, getObjs, getILists, getSysVals, xmlOut);
		}

		public override string getXml(string name, string decoInfo, bool setOnly, bool dirtyOnly, bool newOnly, bool getBasic, bool getObjs, bool getILists, bool getSysVals, XmlTextWriter xmlOut)
		{
			return "<NotDone/>";
		}

		public override void removeAt(int index)
		{
		}

		public override void Clear()
		{

		}


		public override IBizObjCursor createCursor()
		{
			return null;
		}

		public override IBizObj search(string fieldList, object matchValue)
		{
			return null;
		}

		public override IBizObj search(string fieldList, object matchValue, bool findNearestMatch)
		{
			return null;
		}
		#region IGroupedBizObjList Members

		protected abstract void updateStore(IBizObjList groups);
		public void updateStore()
		{
			updateStore(m_groups);
		}

		public IBizObjList ListGroups
		{
			get
			{
				return m_groups;
			}
		}

		#endregion
	}

	[Serializable]
	public class DarVirtualBizObjList : VirtualBizObjList
	{
		private string m_darBaseName;

		public DarVirtualBizObjList(object id, string groupBizObjType, int groupSize, string darBaseName, string bizObjType)
			:base(id, groupSize, groupBizObjType, bizObjType)
		{
			m_darBaseName = darBaseName;
			initialize();
		}

		public override object Clone()
		{
			return null;
		}

		protected override void updateStore(IBizObjList groups)
		{
			foreach(IBizObj group in groups)
			{
				if(group.isNew)
				{
				}
				else if(group.isDirty())
				{
				}
			}
		}

		protected override IBizObjList getBasicGroupList(object id)
		{
			IApplication app = Application.currentApp;
			FlexiMap map = new FlexiMap();
			map["id"] = id;

			//This can thow a DataAccessException, which this method just exposes directly.
			return (IBizObjList)app.appData.get("Data." + m_darBaseName + "GetGroups", map);
		}

		protected override void ensureChildrenAvailable(IBizObjList groups, IBizObj group)
		{
			if(!group.isFieldSet("children"))
			{
				lock(group)
				{
					if(!group.isFieldSet("children"))
					{
						IApplication app = Application.currentApp;
						FlexiMap map = new FlexiMap();
						map.put("id", group.get("id"));
						IBizObjList l = (IBizObjList)app.appData.get("Data." + m_darBaseName + "GetGroupChildren", map);
						if(l.numElements == 1)
						{
							IBizObjList l2 = (IBizObjList)l[0].get("children");
							Console.WriteLine("ensure got {0}", l2.numElements);
							group.put("children", l[0].get("children"));
						}
					}
				}
			}
		}

		protected override IBizObj initializeNewGroup(IBizObjList groups)
		{
			IBizObj newGroup = groups.insertNew();
			return newGroup;
		}

		protected override void updateGroup(IBizObj group)
		{
			IApplication app = Application.currentApp;
			IDictionary map = new Hashtable();
			map["source"] = group;
			string name = "Data." + m_darBaseName + ((group.isNew)?"InsertNewGroup":"UpdateGroup");
			app.appData.get(name, map);
		}


	}

}
